
#include "bsp_config.h"

/**
 *  这里只是对结构体的长度,结构体的名称赋了值 
 */
ConfigParam_Typedef ConfigParam =
    {
        //注意给结构体参数赋值时后面是,号
        .WorkingMode.pC = WORKING_MODE_KEY,
        .WorkingMode.length = sizeof(struct work_mode),

        .WorkingStatus.pC = WORKING_STATUS_KEY,
        .WorkingStatus.length = sizeof(enum status),

        .FumigateSetting.pC = FUMIGATE_SETT_KEY,
        .FumigateSetting.length = sizeof(struct fumigate_sett),

        .RepelSetting.pC = REPELLENT_SETT_KEY,
        .RepelSetting.length = sizeof(struct repel_setts),

        .FactorySetting.pC = FACTORY_SETT_KEY,
        .FactorySetting.length = sizeof(struct factory_sett),

        .BooleanMode.pC = BOOLEAN_KEY,
        .BooleanMode.length = sizeof(struct  boolean_struct),

        .PumpCnt.pC = PUMPCNT_KEY,
        .PumpCnt.length = sizeof(struct pump_cnt),

        .PID_Param.pC = PID_PARAM_KEY,
        .PID_Param.length = sizeof(struct pid_param),

        .MQTT_Param.pC = MQTT_PARAM_KEY,
        .MQTT_Param.length = sizeof(struct mqtt_param),
};

ConfigParam_Typedef ConfigParamDefault = //默认的配置结构体  这里需要对默认的参数进行配置 主要用于备份系统状态
    {
        .WorkingMode.pC = WORKING_MODE_KEY,
        .WorkingMode.length = sizeof(struct work_mode),
        .WorkingMode.work_mode_data.working_mode = WORKING_MODE,
        .WorkingMode.work_mode_data.fumigate_buf_mode = FUMIGATE_BUF_MODE,
        .WorkingMode.work_mode_data.repel_buf_mode = REPEL_BUF_MODE,

        .WorkingStatus.pC = WORKING_STATUS_KEY,
        .WorkingStatus.length = sizeof(enum status),
        .WorkingStatus.working_status_data = WORKING_STATUS,

        .FumigateSetting.pC = FUMIGATE_SETT_KEY,
        .FumigateSetting.length = sizeof(struct fumigate_sett),
        .FumigateSetting.fumi_sett_data.fumi_house_height = FUMI_HOUSE_HEIGHT,
        .FumigateSetting.fumi_sett_data.fumi_sett_area = FUMI_AREA,

        .RepelSetting.pC = REPELLENT_SETT_KEY,
        .RepelSetting.length = sizeof(struct repel_setts),
        .RepelSetting.repel_sett_data.repel_sett_mode = REPEL_SETT_MODE,
        .RepelSetting.repel_sett_data.repel_sett_timing.Start_Hour = REPEL_TIME_START_HOUR,
        .RepelSetting.repel_sett_data.repel_sett_timing.End_Hour = REPEL_TIME_END_HOUR,
        .RepelSetting.repel_sett_data.repel_sett_timing.IsRepeat = false,
        .RepelSetting.repel_sett_data.repel_sett_area = REPEL_AREA_ENUM_MODE,
        .RepelSetting.repel_sett_data.backlight = BACK_LIGHT,
        .RepelSetting.repel_sett_data.total_repel_time = HOURS_OF_REPEL * 3600L,

        .FactorySetting.pC = FACTORY_SETT_KEY,
        .FactorySetting.length = sizeof(struct factory_sett),
        .FactorySetting.factory_sett_data.evacuation_times = 20,
        .FactorySetting.factory_sett_data.fumigate_time = 35,
        .FactorySetting.factory_sett_data.timers_per10m3 = 0.7,
        .FactorySetting.factory_sett_data.air_condi_open_time = 30,
        .FactorySetting.factory_sett_data.air_condi_close_time = 40,
        .FactorySetting.factory_sett_data.maternal_open_time = 30,
        .FactorySetting.factory_sett_data.maternal_close_time = 30,
        .FactorySetting.factory_sett_data.normal_open_time = 60,
        .FactorySetting.factory_sett_data.normal_close_time = 20,
        .FactorySetting.factory_sett_data.area10m2_factory = 60,
        .FactorySetting.factory_sett_data.area20m2_factory = 70,
        .FactorySetting.factory_sett_data.area30m2_factory = 100,
        .FactorySetting.factory_sett_data.InitRepelTime = 30, //初始化驱蚊部分

        .BooleanMode.pC = BOOLEAN_KEY,
        .BooleanMode.length = sizeof(struct  boolean_struct),
        .BooleanMode.boolean_struct_data.sound_status_data = SOUNG_MODE,
        // .BooleanMode.boolean_struct_data.wifi_or_ble=WIFI_BLE_MODE,

        .PumpCnt.pC = PUMPCNT_KEY,
        .PumpCnt.length = sizeof(struct pump_cnt),
        .PumpCnt.pump_cnt_data.pumpcnt = PUMP_COUNTER,
        .PumpCnt.pump_cnt_data.need_evacuation = EVACUATE_OR_NOT,
        .PumpCnt.pump_cnt_data.is_empty = EMPTY_OR_NOT,
        .PumpCnt.pump_cnt_data.type = MEDICINE_TYPE,

        .PID_Param.pC = PID_PARAM_KEY,
        .PID_Param.length = sizeof(struct pid_param),
        .PID_Param.pid_param_data.SetPoint = TARGET_TEMP,
        .PID_Param.pid_param_data.SetPointBackup = TARGET_TEMP, //这个主要是针对
        .PID_Param.pid_param_data.Proportion = P,
        .PID_Param.pid_param_data.Integral = I,
        .PID_Param.pid_param_data.Derivative = D,
        .PID_Param.pid_param_data.Self_Tuning_Flag = SELF_TUNING_FLAG, //默认是需要自整定的

        .MQTT_Param.pC = MQTT_PARAM_KEY,
        .MQTT_Param.length = sizeof(struct mqtt_param),
        .MQTT_Param.mqtt_param_data.wifi_ssid = "TP-LINK_B282",
        .MQTT_Param.mqtt_param_data.wifi_password = "sk123456789",
        .MQTT_Param.mqtt_param_data.wifi_maximum_retry = 20,
        .MQTT_Param.mqtt_param_data.wifi_mode = WIFI_MODE,
        .MQTT_Param.mqtt_param_data.mqtt_topic = "ESP32MWQA0B0C0D0E0F0", //长度
};

/***********************************这些是单独的数据读写函数 批量读写不用这个函数**************************************************/
/**
 *  @brief  从NVS中读取WIFI的相关参数
 *  @param  pData :指向存储读取到的数据的指针
 *  @param  pChar :指向KEY字符串的指针
 *  @param  length:指向待获取数据的长度的指针
 *  @retval 无
 */
void read_config_param(void *pData, void *pChar, void *length)
{
    nvs_handle_t my_handle;
    uint32_t leng = 0;

    //读取数据之前得将原数据擦去,以免产生干扰
    memset(pData, 0, *((uint32_t *)length));
    ESP_ERROR_CHECK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle));

    nvs_get_blob(my_handle, pChar, NULL, (size_t *)(&leng));
    if (leng == 0)
    {
        printf("KEY %s Nothing saved yet!\n", pChar);
    }
    else
    {
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, pChar, pData, (size_t *)length));
    }

    nvs_close(my_handle);
    printf("%s\n", "read param from nvs");
}

/**
 *  @brief  将相关参数写入NVS中   用于一个结构体存储
 *  @param  pData :指向存储待写入的数据的指针
 *  @param  pChar :指向KEY字符串的指针
 *  @param  length:指向待写入数据的长度的指针
 *  @retval 无
 */
void write_config_param(void *pData, void *pChar, uint32_t length)
{
    nvs_handle_t my_handle;
    // Open
    ESP_ERROR_CHECK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle)); //namespace

    ESP_ERROR_CHECK(nvs_set_blob(my_handle, pChar, pData, length)); //要从指针中取数值,首先得将其转换成相应的指针类型

    ESP_ERROR_CHECK(nvs_commit(my_handle));

    nvs_close(my_handle);
    //printf("%s\n", "write param to nvs");
}

/***********************************************************************************************/
/**
 *  @brief  读取NVS中的系统参数,每次上电后进行   在vim中不需要ctrl + S
 *  @param  无
 *  @retval 是否需要将默认值写入NVS中 相当于恢复出场设置  
 *          1:表示需要重置
 *          0:表示不需要重置
 */
static uint8_t ParamRead(void)
{
    nvs_handle_t my_handle;
    uint32_t length = 0;
    uint8_t need_reset = 0;

    //读取数据之前得将原数据擦去,以免产生干扰
    memset(&ConfigParam.WorkingMode.work_mode_data.working_mode, 0, ConfigParam.WorkingMode.length);
    memset(&ConfigParam.WorkingStatus.working_status_data, 0, ConfigParam.WorkingStatus.length);
    memset(&ConfigParam.FumigateSetting.fumi_sett_data.fumi_house_height, 0, ConfigParam.FumigateSetting.length);
    memset(&ConfigParam.RepelSetting.repel_sett_data.repel_sett_mode, 0, ConfigParam.RepelSetting.length);
    memset(&ConfigParam.FactorySetting.factory_sett_data.evacuation_times, 0, ConfigParam.FactorySetting.length);
    memset(&ConfigParam.BooleanMode.boolean_struct_data.sound_status_data, 0, ConfigParam.BooleanMode.length);
    memset(&ConfigParam.PumpCnt.pump_cnt_data.pumpcnt, 0, ConfigParam.PumpCnt.length);
    memset(&ConfigParam.PID_Param.pid_param_data.SetPoint, 0, ConfigParam.PID_Param.length); //如果有其他数据,这里还得进行重置
    memset(&ConfigParam.MQTT_Param.mqtt_param_data.wifi_ssid, 0, ConfigParam.MQTT_Param.length);

    ESP_ERROR_CHECK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle));

    printf("%s\n", "read param from nvs");
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.WorkingMode.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.WorkingMode.pC);
        need_reset++; //需要重置
    }
    else
    {
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.WorkingMode.pC, &ConfigParam.WorkingMode.work_mode_data.working_mode, (size_t *)(&ConfigParam.WorkingMode.length)));
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.WorkingStatus.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.WorkingStatus.pC);
        need_reset++; //需要重置
    }
    else
    { //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.WorkingStatus.pC, &ConfigParam.WorkingStatus.working_status_data, (size_t *)(&ConfigParam.WorkingStatus.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.FumigateSetting.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.FumigateSetting.pC);
        need_reset++; //需要重置
    }
    else
    { //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.FumigateSetting.pC, &ConfigParam.FumigateSetting.fumi_sett_data.fumi_house_height, (size_t *)(&ConfigParam.FumigateSetting.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.RepelSetting.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.RepelSetting.pC);
        need_reset++; //需要重置
    }
    else //
    {    //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.RepelSetting.pC, &ConfigParam.RepelSetting.repel_sett_data.repel_sett_mode, (size_t *)(&ConfigParam.RepelSetting.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.FactorySetting.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.FactorySetting.pC);
        need_reset++; //需要重置
    }
    else //
    {    //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.FactorySetting.pC, &ConfigParam.FactorySetting.factory_sett_data.evacuation_times, (size_t *)(&ConfigParam.FactorySetting.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.BooleanMode.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.BooleanMode.pC);
        need_reset++; //需要重置
    }
    else //
    {    //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.BooleanMode.pC, &ConfigParam.BooleanMode.boolean_struct_data.sound_status_data, (size_t *)(&ConfigParam.BooleanMode.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.PumpCnt.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.PumpCnt.pC);
        need_reset++; //需要重置
    }
    else //
    {    //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.PumpCnt.pC, &ConfigParam.PumpCnt.pump_cnt_data.pumpcnt, (size_t *)(&ConfigParam.PumpCnt.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.PID_Param.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.PID_Param.pC);
        need_reset++; //需要重置
    }
    else //
    {    //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.PID_Param.pC, &ConfigParam.PID_Param.pid_param_data.SetPoint, (size_t *)(&ConfigParam.PID_Param.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    /*********************************************************************************************************************************/
    nvs_get_blob(my_handle, ConfigParam.MQTT_Param.pC, NULL, (size_t *)(&length));
    if (length == 0)
    {
        printf("KEY %s Nothing saved yet!\n", ConfigParam.MQTT_Param.pC);
        need_reset++; //需要重置
    }
    else //
    {    //这里是读取到了数据
        ESP_ERROR_CHECK(nvs_get_blob(my_handle, ConfigParam.MQTT_Param.pC, &ConfigParam.MQTT_Param.mqtt_param_data.wifi_ssid, (size_t *)(&ConfigParam.MQTT_Param.length)));
        //这里只管打印
    }
    /*********************************************************************************************************************************/
    nvs_close(my_handle);

    return (need_reset);
}

/**
 *  @brief  将默认的参数写入NVS中
 *  @param  无
 *  @retval 无
 */
static void WriteDefaultParam(void)
{
    nvs_handle_t my_handle;

    ESP_ERROR_CHECK(nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle));

    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.WorkingMode.pC, &ConfigParamDefault.WorkingMode.work_mode_data.working_mode, ConfigParamDefault.WorkingMode.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.WorkingStatus.pC, &ConfigParamDefault.WorkingStatus.working_status_data, ConfigParamDefault.WorkingStatus.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.FumigateSetting.pC, &ConfigParamDefault.FumigateSetting.fumi_sett_data.fumi_house_height, ConfigParamDefault.FumigateSetting.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.RepelSetting.pC, &ConfigParamDefault.RepelSetting.repel_sett_data.repel_sett_mode, ConfigParamDefault.RepelSetting.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.FactorySetting.pC, &ConfigParamDefault.FactorySetting.factory_sett_data.evacuation_times, ConfigParamDefault.FactorySetting.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.BooleanMode.pC, &ConfigParamDefault.BooleanMode.boolean_struct_data.sound_status_data, ConfigParamDefault.BooleanMode.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.PumpCnt.pC, &ConfigParamDefault.PumpCnt.pump_cnt_data.pumpcnt, ConfigParamDefault.PumpCnt.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.PID_Param.pC, &ConfigParamDefault.PID_Param.pid_param_data.SetPoint, ConfigParamDefault.PID_Param.length));
    ESP_ERROR_CHECK(nvs_set_blob(my_handle, ConfigParamDefault.MQTT_Param.pC, &ConfigParamDefault.MQTT_Param.mqtt_param_data.wifi_ssid, ConfigParamDefault.MQTT_Param.length));

    ESP_ERROR_CHECK(nvs_commit(my_handle));

    nvs_close(my_handle);
}

/**
 *  @brief  对相关参数进行初始化,如果是初次使用则写入初始参数,否则读取相关参数   一定得在app_main函数中调用
 *  @param  无
 *  @retval 无
 */
void ConfigParamInit(void)
{
    esp_err_t ret;

    // Initialize NVS.
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        printf("nvs flash erase init\n");
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    if (ParamRead())
    {                                         //初次使用
        printf("第一次使用,将默认参数写进Nvs Flash");
        WriteDefaultParam();                  //写入参数之前也得将载具清洗干净!
        vTaskDelay(500 / portTICK_PERIOD_MS); //延时500ms
        ParamRead();
    }
}
